/*
 * Created by SharpDevelop.
 * User: Michael
 * Date: 17/09/2007
 * Time: 5:06 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;

namespace SudokuSolver
{
	/// <summary>
	/// Single Option is an agressive technique which, for each group (column, row, block) generates a list
	/// of missing numbers. It then counts, for each number that's missing, how many cells have that number
	/// in their candidate list. If only one cell in a row/column/block can contain one of the missing numbers,
	/// that number is assigned to that cell.
	/// </summary>
	public class SingleOption : Technique
	{
		private int CountPlacesForNumber(Group thisGroup, int number)
		{
			int count = 0;
			foreach(Cell cell in thisGroup.Cells)
			{
				if(cell.IsPossible(number))
					count++;
			}
			return count;
		}
		
		public void AssignNumberInGroup(Group theGroup, int number)
		{
			foreach(Cell cell in theGroup.Cells)
			{
				if(cell.IsPossible(number))
				{
					cell.Value = number;
					//Console.WriteLine("Single Option found that " + Cell.RowNumber + "," + cell.Column + " contains " + cell.Value);
					return;
				}
			}
		}
		
		public override bool Run(SudokuGame theGame)
		{
			//Console.WriteLine("Starting SingleOption...");
			//find out what values are missing from each block
			//see if theres only one place for it to go
			//if there is, put it in there
			
			bool changed = false;
			//for each number
			for(int number = 1; number <= 9; number++)
			{
				//check each group
				foreach(Group thisGroup in theGame.Rows)
				{
					//if this group is missing the number
					if(thisGroup.MissingNumber(number))
					{
						//if only one place can take this number
						if(CountPlacesForNumber(thisGroup, number) == 1)
						{
							AssignNumberInGroup(thisGroup, number);
							
							//something has changed!
							changed = true;
						}
					}
				}
				foreach(Group thisGroup in theGame.Columns)
				{
					//if this group is missing the number
					if(thisGroup.MissingNumber(number))
					{
						//if only one place can take this number
						if(CountPlacesForNumber(thisGroup, number) == 1)
						{
							AssignNumberInGroup(thisGroup, number);
							//something has changed!
							changed = true;
						}
					}
				}
				foreach(Group thisGroup in theGame.Blocks)
				{
					//if this group is missing the number
					if(thisGroup.MissingNumber(number))
					{
						//if only one place can take this number
						if(CountPlacesForNumber(thisGroup, number) == 1)
						{
							AssignNumberInGroup(thisGroup, number);
							//something has changed!
							changed = true;
						}
					}
				}
			}
			
			return changed;
		}
		
		public override string ToString()
		{
			return base.ToString() + ": Single Option";
		}
	}
}
